<!DOCTYPE html>
<html>
    <head>

        <link rel="canonical" href="http://www.jointjs.com/" />
        <meta name="description" content="Create interactive diagrams in JavaScript easily. JointJS plugins for ERD, Org chart, FSA, UML, PN, DEVS, LDM diagrams are ready to use." />
        <meta name="keywords" content="JointJS, JavaScript, diagrams, diagramming library, UML, charts" />

        <link href="http://fonts.googleapis.com/css?family=Source+Sans+Pro:400,700" rel="stylesheet" type="text/css" />
        <link href="https://fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet">

        <link rel="stylesheet" href="css/tutorial.css" />
        <link rel="stylesheet" href="../node_modules/prismjs/themes/prism.css">


        <!-- Dependencies: -->
        <script src="../node_modules/jquery/dist/jquery.js"></script>
        <script src="../node_modules/lodash/lodash.js"></script>
        <script src="../node_modules/backbone/backbone.js"></script>


        <link rel="stylesheet" type="text/css" href="../build/joint.min.css" />
        <script type="text/javascript" src="../build/joint.min.js"></script>

        <title>JointJS - JavaScript diagramming library - Getting started.</title>

    </head>
    <body class="language-javascript tutorial-page">

        <script>
            SVGElement.prototype.getTransformToElement = SVGElement.prototype.getTransformToElement || function(toElement) {
                return toElement.getScreenCTM().inverse().multiply(this.getScreenCTM());
            };
        </script>

        <div id="custom-elements" class="tutorial">

            <h2>Custom Links</h2>

            <p>This is the fifth article of the intermediate section of the JointJS tutorial.
                <a href="custom-elements.html">Go back to custom elements.</a>
                Alternatively, you can <a href="intermediate.html">return to index</a> of all articles.</p>

            <p>JointJS comes with several built-in link shapes; we have already encountered
                <code>joint.shapes.standard.Link</code> in the <a href="links.html">basic links</a> tutorial.</p>

            <p>However, builtin link definitions are not as plentiful as element definitions.
                It is thus very possible that you will find the need to define your own custom link type.
                Creating custom links is very similar to <a href="custom-elements.html">creating custom elements</a>,
                with a few differences.
                <a href="/docs/jointjs#dia.Link" target="_blank">The Link class is discussed in JointJS documentation,
                as well.</a></p>

            <p>A new Link subtype is registered by calling the <code>define()</code> function:</p>

            <ul>
                <li><a href="/docs/jointjs#dia.Cell.define" target="_blank"><code>Link.define(type [, defaultInstanceProperties, prototypeProperties, staticProperties])</code></a>
                - define a new subtype of this <code>Link</code> class.</li>
            </ul>

            <p>If you want to create a Link subtype from scratch, you should inherit from the default
                <code>joint.dia.Link</code> class by calling <code>joint.dia.Link.define()</code>.
                You can also inherit from any predefined link (e.g. <code>joint.shapes.standard.Link.define()</code>)
                and even any custom link subtype you have previously defined.</p>

            <p>Here is how the parameters of the <code>define()</code> function map to familiar building blocks of
                links:</p>

            <ul>
                <li><code>type</code> - the <a href="#name">name</a> of the subtype class.</li>
                <li><code>defaultInstanceProperties</code> - object that contains properties to be assigned to every
                constructed instance of the subtype.
                Used for specifying <a href="#default-attributes">default attributes</a>.</li>
                <li><code>prototypeProperties</code> - object that contains properties to be assigned on the subtype
                prototype.
                Intended for properties intrinsic to the subtype, not usually modified.
                Used for specifying shape <a href="#markup">markup</a>.</li>
                <li><code>staticProperties</code> - object that contains properties to be assigned on the subtype
                constructor.
                Not very common, used mostly for <a href="#static-properties">alternative constructor
                functions</a>.</li>
            </ul>

            <p>Let us use the familiar
                <a href="/docs/jointjs#shapes.standard.Link" target="_blank"><code>joint.shapes.standard.Link</code></a>
                shape definition as an example:</p>

            <pre><code>joint.dia.Link.define('standard.Link', {
    attrs: {
        line: {
            connection: true,
            stroke: '#333333',
            strokeWidth: 2,
            strokeLinejoin: 'round',
            targetMarker: {
                'type': 'path',
                'd': 'M 10 -5 0 0 10 5 z'
            }
        },
        wrapper: {
            connection: true,
            strokeWidth: 10,
            strokeLinejoin: 'round'
        }
    }
}, {
    markup: [{
        tagName: 'path',
        selector: 'wrapper',
        attributes: {
            'fill': 'none',
            'cursor': 'pointer',
            'stroke': 'transparent'
        }
    }, {
        tagName: 'path',
        selector: 'line',
        attributes: {
            'fill': 'none',
            'pointer-events': 'none'
        }
    }]
});</code></pre>

            <h3 id="name">Name</h3>

            <p>The first argument of the <code>define()</code> function is a unique identifier under which you want to
                be able to find the new type.
                The first part of the name, <code>joint.shapes</code>, is implied.
                Thus, we can see that the name of a type accessed as <code>joint.shapes.standard.Link</code> has to
                be <code>'standard.Link'</code>.</p>

            <h3 id="markup">Markup</h3>

            <p>Markup is usually provided inside the third argument of the <code>define()</code> function (prototype
                properties) for improved performance.
                (This is because markup is something that all instances of the link type are expected to have in
                common, so inheriting from subtype prototype is more efficient.
                Nevertheless, it is still possible to provide custom markup to individual instances of your class by
                providing individual <code>markup</code> later.)</p>

            <p>The <code>markup</code> property is specified as a JSON array.
                Each member of the array is taken to define one subelement of the new shape.
                Subelements are defined with objects containing a <code>tagName</code> (a string with the SVG tag
                name of the subelement) and a <code>selector</code> (a string identifier for this subelement
                in the shape).
                Although JointJS can also understand SVG markup in string form, that approach is noticeably slower due
                to the need for parsing and lack of capacity for custom selectors.</p>

            <p>A <code>joint.shapes.standard.Link</code> is composed of two subelements - an
                SVGPathElement named <code>line</code> and an SVGPathElement named <code>wrapper</code>.
                The <code>line</code> is the subelement that is supposed to be styled, while <code>wrapper</code> is a
                transparent helper subelement underneath the <code>line</code> that is designed to be interacted
                with.</p>

            <pre><code>{
    markup: [{
        tagName: 'path',
        selector: 'wrapper',
        attributes: {
            'fill': 'none',
            'cursor': 'pointer',
            'stroke': 'transparent'
        }
    }, {
        tagName: 'path',
        selector: 'line',
        attributes: {
            'fill': 'none',
            'pointer-events': 'none'
        }
    }]
}</code></pre>

            <p>As you can see, <code>attributes</code> can also be defined inside markup.
                These are intended for attributes that all instances of a link type are expected to have in common;
                for such attributes, it is more efficient to inherit these attributes from the subtype prototype instead
                of each instance having their own copy because it avoids unnecessary iterations in the cell attributes
                update loop.
                (Nevertheless, again, it is possible to overwrite these prototype attributes by individual instance
                attributes if absolutely necessary.)</p>

            <p>In our example, <code>markup.attributes</code> are used to reflect the intended use of the two
                subelements of the link, which is not expected to change - <code>wrapper</code> has a transparent stroke
                since it is not expected to be styled, while <code>line</code> has <code>'pointer-events'</code>
                deactivated since it is not expected to be interacted with.
                Both subelement paths also remove the default SVGPathElement <code>'fill'</code> which is not usually
                terribly useful within links.</p>

            <p>An important caveat is that <code>markup.attributes</code> can only store <i>native SVG attributes</i>,
                not JointJS attrs.
                This means that JointJS special attributes are not recognized (since <code>markup.attributes</code> are
                supposed not to change, they would not be able to reflect possible changes in referenced subelements or in the
                size/position of model bbox).
                Additionally, this means that there is no JointJS kebab-case translation of attribute names; thus, using
                quotes around all attribute names is encouraged in this context, to communicate these restrictions to
                programmers (i.e. <code>'fill'</code>, not <code>fill</code>; <code>'pointer-events'</code>, not
                <code>pointerEvents</code>).</p>

            <h3 id="default-attributes">Default Attributes</h3>

            <p>Default attributes are usually provided inside the second argument of the <code>define()</code> function
                (default instance properties).
                (This is because all instances of the link type are expected to have their own individual attributes, so
                inheriting from the prototype is likely to cause unnecessary overhead.)</p>

            <p>In the <code>attrs</code> object, keys correspond to subelement selectors, as defined in the
                <a href="#markup">markup</a>.
                For each subelement, an object with attribute name-value pairs is then expected.
                Each of these attributes can be a native SVG attribute or a <a href="special-attributes.html">JointJS
                special attribute</a>.</p>

            <p>In <code>joint.shapes.standard.Link</code>, we can see that the subelement referenced by
                <code>line</code> (i.e. the stylable SVGPathElement component of the link) has a default dark-gray
                stroke of width <code>2</code>, and a default target marker that looks like a small arrow.
                (Since the default target marker has no <code>fill</code> or <code>stroke</code> set, the colors are
                inherited from the <code>line.stroke</code> attribute by default.)
                The <code>wrapper</code> subelement (the interactive SVGPathElement component of the link) has a wider
                transparent stroke to make the link easier to click for users.
                Finally, notice that both subelements have the <code>connection</code>
                <a href="special-attributes.html#link-relative-position">special attribute</a> set to
                <code>true</code>.
                This means that they both automatically follow the connection path of the link instance as calculated by
                the <a href="links.html#link-geometry">link geometry functions</a>:</p>

            <pre><code>{
    attrs: {
        line: {
            connection: true,
            stroke: '#333333',
            strokeWidth: 2,
            strokeLinejoin: 'round',
            targetMarker: {
                'type': 'path',
                'd': 'M 10 -5 0 0 10 5 z'
            }
        },
        wrapper: {
            connection: true,
            strokeWidth: 10,
            strokeLinejoin: 'round'
        }
    }
}</code></pre>

            <h3 id="default-label">Default Label</h3>

            <p>The second argument of the <code>define()</code> function (default instance properties) is also where
                <code>defaultLabel</code> for custom Link subtypes may be specified.
                This allows you to provide custom default markup and attrs for labels that are created on an instance of
                your custom Link type.
                The <code>joint.shapes.standard.Link</code>
                <a href="/docs/jointjs#dia.Link.intro.customLink" target="_blank">does not define its own custom default
                label</a>, so the
                <a href="/docs/jointjs#dia.Link.intro.builtinDefaultAttributes" target="_blank">builtin default markup
                and attributes</a> are used unless they are overridden by individual label <code>markup</code> and
                <code>attrs</code>.</p>

            <p>The <code>defaultLabel</code> accepts three properties:</p>

            <ul>
                <li><code>defaultLabel.markup</code> - sets the default markup of labels created on this Link subtype.
                Expected in the JSON markup format.</li>
                (An SVG-parsable string is also accepted, but it is slower.)
                <a href="/docs/jointjs#dia.Link.intro.builtinDefaultAttributes" target="_blank">See default.</a></li>
                <li><code>defaultLabel.attrs</code> - sets the default attributes of label subelements on this Link
                subtype.
                Uses selectors defined in <code>markup</code>.
                <a href="/docs/jointjs#dia.Link.intro.builtinDefaultAttributes" target="_blank">See default.</a></li>
                <li><code>defaultLabel.position</code> - sets the default position along the line at which labels will
                be added for instances of this Link subtype.
                Default is <code>0.5</code> (midpoint of the connection path).</li>
            </ul>

            <p><a href="link-labels.html">Link labels are explained in depth in a separate section of the intermediate
                tutorial.</a></p>

            <h3 id="static-properties">Static Properties</h3>

            <p>Static properties are not used by <code>joint.shapes.standard.Link</code>, but let us discuss them a
                little bit to gain a complete overview of custom links.</p>

            <p>Similarly to our <a href="custom-elements.html#static-properties">custom element example</a>, imagine we
                wanted to define our own subtype of <code>joint.shapes.standard.Link</code> (which we name
                <code>'examples.CustomLink'</code>), with the added benefit of a constructor function that
                chose a random style for the link's line - maybe because we need to add a lot of diverse links quickly.
                We could do this with a static function <code>createRandom</code>; then, we would have two ways to
                obtain an instance of CustomLink:</p>

            <p>With the standard constructor ...</p>

            <pre><code>var customLink = new joint.shapes.examples.CustomLink();</code></pre>

            <p>... or with the new static function:</p>

            <pre><code>var customLink = joint.shapes.examples.CustomLink.createRandom();</code></pre>

            <p>Both of these functions are demonstrated in our <a href="#example">example</a>.</p>

            <h3 id="example">Example</h3>

            <p>Let us apply everything we learned so far and create a new
                <cdoe>joint.shapes.examples.CustomLink</cdoe> class based on <code>joint.shapes.standard.Link</code>.
                Keep in mind that the provided instance properties are mixined with the parent definition, but prototype
                and static properties are not.
                This means that it is enough for us to record only the attributes that changed in the definition of the
                custom element subtype (however, if we wanted to change the markup, we would have to do so
                explicitly).</p>

            <pre><code>joint.shapes.standard.Link.define('examples.CustomLink', {
    attrs: {
        line: {
            stroke: 'cornflowerblue',
            strokeWidth: 5,
            targetMarker: {
                'type': 'rect',
                'width': 10,
                'height': 20,
                'y': -10,
                'stroke': 'none'
            }
        }
    },
    defaultLabel: {
        markup: [
            {
                tagName: 'rect',
                selector: 'body'
            }, {
                tagName: 'text',
                selector: 'label'
            }
        ],
        attrs: {
            label: {
                fill: 'black', // default text color
                fontSize: 12,
                textAnchor: 'middle',
                yAlignment: 'middle',
                pointerEvents: 'none'
            },
            body: {
                ref: 'label',
                fill: 'white',
                stroke: 'cornflowerblue',
                strokeWidth: 2,
                refWidth: '120%',
                refHeight: '120%',
                refX: '-10%',
                refY: '-10%'
            }
        },
        position: {
            distance: 100, // default absolute position
            args: {
                absoluteDistance: true
            }
        }
    }
}, {
    // inherit joint.shapes.standard.Link.markup
}, {
    createRandom: function() {

        var link = new this();

        var stroke = '#' + ('000000' + Math.floor(Math.random() * 16777215).toString(16)).slice(-6);
        var strokeWidth = Math.floor(Math.random() * 10) + 1;
        var strokeDasharray = (Math.floor(Math.random() * 5) + 1) + ' ' + (Math.floor(Math.random() * 5) + 1);

        link.attr({
            line: {
                stroke: stroke,
                strokeWidth: strokeWidth,
                strokeDasharray: strokeDasharray
            }
        });

        link.prop('defaultLabel/attrs/body/stroke', stroke);

        return link;
    }
});</code></pre>

            <p>The following example shows the default look of <code>joint.shapes.standard.Link</code> (i.e. with no
                instance attributes set) alongside the default look of our custom link and the randomized results of the
                <code>createRandom()</code> constructor function.
                Every link has a default label added as well.
                Try <a onClick="window.location.reload()" style="cursor: pointer">refreshing the page</a> to see
                <code>createRandom()</code> in action.</p>

            <div class="paper" id="paper-custom-links"></div>

            <p>JointJS source code: <a href="js/custom-links.js" target="_blank">custom-links.js</a></p>

            <p><a href="link-labels.html">In the next section of the intermediate tutorial, we will learn about link
                labels.</a></p>

        </div><!--end tutorial-->

        <script src="../node_modules/prismjs/prism.js"></script>

        <script src="js/custom-links.js"></script>
    </body>
</html>
